package pl.edu.agh.view;

import com.vaadin.Application;
import com.vaadin.data.Property;
import com.vaadin.ui.*;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.vaadin.vaadinvisualizations.AnnotatedTimeLine;
import org.vaadin.vaadinvisualizations.AnnotatedTimeLineEntry;
import pl.edu.agh.controller.MainController;
import pl.edu.agh.model.core.Price;
import pl.edu.agh.types.SlopeType;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;



public class WebApp  extends Application {
    private Logger log = Logger.getLogger(WebApp.class);
    private ApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/application-context.xml");
    private VerticalLayout mainLayout = new VerticalLayout();

    public void init() {
        log.info("Starting web application");

        final Window window = new Window();
        setMainWindow(window);
        window.setContent(mainLayout);

        final MainController controller = context.getBean(MainController.class);

        Label info = new Label("Stock: " + controller.getDesc() + ", initial money: " + controller.getInitialMoney());
        mainLayout.addComponent(info);


        final AbstractSelect slopeSelect = new NativeSelect("Choose slope to play on");
        for (SlopeType type: SlopeType.values()) {
            slopeSelect.addItem(type);
            slopeSelect.setItemCaption(type, type + " SLOPE");
        }

        slopeSelect.setNullSelectionAllowed(false);
        slopeSelect.setValue(2);
        slopeSelect.setImmediate(true);

        slopeSelect.addListener(new Property.ValueChangeListener() {
            @Override
            public void valueChange(Property.ValueChangeEvent valueChangeEvent) {
                try{
                    switch ((SlopeType) valueChangeEvent.getProperty().getValue()){
                        case STABLE: createChart("Stable slope", controller.getStableSlopeBuyAndHoldIncome(), controller.getStableSlopeGPIncome(), controller);
                            break;
                        case UP: createChart("Up slope", controller.getUpSlopeBuyAndHoldIncome(), controller.getUpSlopeGPIncome(), controller);
                            break;
                        case DOWN: createChart("Down slope", controller.getDownSlopeBuyAndHoldIncome(), controller.getDownSlopeGPIncome(), controller);
                            break;
                        case MIXED: createChart("Mixed slope", controller.getMixedSlopeBuyAndHoldIncome(), controller.getMixedSlopeGPIncome(), controller);
                            break;
                        case GOOG: createChart("GOOG", controller.getGoogSlopeBuyAndHoldIncome(), controller.getGoogSlopeGPIncome(), controller);
                            break;
                    }
                }catch(Exception e){
                    log.info("Chart can't be printed.");
                }
            }
        });

        mainLayout.addComponent(slopeSelect);
    }

    private void createChart(String labelDesc, List<Price> bhIncome, List<Price> gpIncome, MainController controller) {
        mainLayout.addComponent(new Label(labelDesc));
        AnnotatedTimeLine priceChart = addPriceChartTo(mainLayout);
        addPricesToChart(bhIncome, gpIncome, priceChart);

        mainLayout.addComponent(new Label("Best fitness (over B&H): " + normlizeFitness(controller.getBestFitness())));
        mainLayout.addComponent(new Label("Total won: " + controller.getTotalWon()));
        mainLayout.addComponent(new Label("Won strategy: " + controller.getAllTimeBest()));
    }

    private String normlizeFitness(double bestFitness) {
        double withHoundreths = (long) bestFitness * 100l;
        return withHoundreths/100.0 + "";
    }

    private void addPricesToChart(List<Price> income, List<Price> gpIncome, AnnotatedTimeLine priceChart) {
        for(Price price:income){
            Price gpPrice = gpIncome.get(income.indexOf(price));
            ArrayList<AnnotatedTimeLineEntry> timeLineEntries = new ArrayList<AnnotatedTimeLineEntry>();
            timeLineEntries.add(new AnnotatedTimeLineEntry(price.getIncome(),"",""));
            timeLineEntries.add(new AnnotatedTimeLineEntry(gpPrice.getIncome(),"",""));

            Calendar calendar = new GregorianCalendar();
            calendar.setTime(price.getDate());
            priceChart.add(calendar, timeLineEntries);
        }
    }

    private AnnotatedTimeLine addPriceChartTo(VerticalLayout layout){
        AnnotatedTimeLine priceChart = new AnnotatedTimeLine();
        priceChart.setHeight("300px");
        priceChart.setWidth("700px");
        priceChart.setOption("legend", "right");
        priceChart.setOption("displayAnnotations", true);
        priceChart.setOption("wmode", "opaque");
        priceChart.setOption("scaleType", "maximized");

        priceChart.addLineLabel("Buy&Hold");
        priceChart.addLineLabel("GP");

        layout.addComponent(priceChart);

        return priceChart;
    }
}
